<template>
  <Form v-bind="getBindValue" :class="getFormClass" ref="formElRef" :model="formModel"
    @keypress.enter="handleEnterPress">
    <Row v-bind="getRow">
      <slot name="formHeader"></slot>
      <template v-for="schema in getSchema" :key="schema.field">
        <FormItem :tableAction="tableAction" :formActionType="formActionType" :schema="schema" :formProps="getProps"
          :allDefaultValues="defaultValueRef" :formModel="formModel" :formName="getBindValue.name"
          :setFormModel="setFormModel" :validateFields="validateFields" :clearValidate="clearValidate"
          v-auth="schema.auth">
          <template #[item]="data" v-for="item in Object.keys($slots)">
            <slot :name="item" v-bind="data || {}"></slot>
          </template>
        </FormItem>
      </template>

      <FormAction v-bind="getFormActionBindProps" @toggle-advanced="handleToggleAdvanced">
        <template #[item]="data" v-for="item in ['resetBefore', 'submitBefore', 'advanceBefore', 'advanceAfter']">
          <slot :name="item" v-bind="data || {}"></slot>
        </template>
      </FormAction>
      <slot name="formFooter"></slot>
    </Row>
  </Form>
</template>
<script lang="ts">
import type { FormActionType, FormProps, FormSchema } from './types/form';
import type { AdvanceState } from './types/hooks';
import type { Ref } from 'vue';

import { defineComponent, reactive, ref, computed, unref, onMounted, watch, nextTick } from 'vue';
import { Form, Row } from 'ant-design-vue';
import FormItem from './components/FormItem.vue';
import FormAction from './components/FormAction.vue';

import { dateItemType } from './helper';
import { dateUtil } from '/@/utils/dateUtil';

// import { cloneDeep } from 'lodash-es';
import { deepMerge } from '/@/utils';

import { useFormValues } from './hooks/useFormValues';
import useAdvanced from './hooks/useAdvanced';
import { useFormEvents } from './hooks/useFormEvents';
import { createFormContext } from './hooks/useFormContext';
import { useAutoFocus } from './hooks/useAutoFocus';
import { useModalContext } from '/@/components/Modal';

import { basicProps } from './props';
import componentSetting from '/@/settings/componentSetting';

import { useDesign } from '/@/hooks/web/useDesign';
import dayjs from 'dayjs';
import { useDebounceFn } from '@vueuse/core';

export default defineComponent({
  name: 'BasicForm',
  components: { FormItem, Form, Row, FormAction },
  props: basicProps,
  emits: ['advanced-change', 'reset', 'submit', 'register'],
  setup(props, { emit, attrs }) {
    const formModel = reactive<Recordable>({});
    const modalFn = useModalContext();

    const advanceState = reactive<AdvanceState>({
      // 默认是收起状态
      isAdvanced: false,
      hideAdvanceBtn: true,
      isLoad: false,
      actionSpan: 6,
    });

    const defaultValueRef = ref<Recordable>({});
    const isInitedDefaultRef = ref(false);
    const propsRef = ref<Partial<FormProps>>({});
    const schemaRef = ref<Nullable<FormSchema[]>>(null);
    const formElRef = ref<Nullable<FormActionType>>(null);

    const { prefixCls } = useDesign('basic-form');

    // Get the basic configuration of the form
    const getProps = computed((): FormProps => {
      let mergeProps = { ...props, ...unref(propsRef) } as FormProps;
      //update-begin-author:sunjianlei date:20220923 for: 如果用户设置了labelWidth，则使labelCol失效，解决labelWidth设置无效的问题
      if (mergeProps.labelWidth) {
        mergeProps.labelCol = undefined;
      }
      //update-end-author:sunjianlei date:20220923 for: 如果用户设置了labelWidth，则使labelCol失效，解决labelWidth设置无效的问题
      // update-begin--author:liaozhiyang---date:20231017---for：【QQYUN-6566】BasicForm支持一行显示(inline)
      if (mergeProps.layout === 'inline') {
        if (mergeProps.labelCol === componentSetting.form.labelCol) {
          mergeProps.labelCol = undefined;
        }
        if (mergeProps.wrapperCol === componentSetting.form.wrapperCol) {
          mergeProps.wrapperCol = undefined;
        }
      }
      // update-end--author:liaozhiyang---date:20231017---for：【QQYUN-6566】BasicForm支持一行显示(inline)
      return mergeProps;
    });

    const getFormClass = computed(() => {
      return [
        prefixCls,
        {
          [`${prefixCls}--compact`]: unref(getProps).compact,
          'jeecg-form-detail-effect': unref(getProps).disabled
        },
      ];
    });

    // Get uniform row style and Row configuration for the entire form
    const getRow = computed((): Recordable => {
      const { baseRowStyle = {}, rowProps } = unref(getProps);
      return {
        style: baseRowStyle,
        ...rowProps,
      };
    });

    const getBindValue = computed(() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable));

    const getSchema = computed((): FormSchema[] => {
      const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
      for (const schema of schemas) {
        const { defaultValue, component, componentProps } = schema;
        // handle date type
        if (defaultValue && dateItemType.includes(component)) {
          //update-begin---author:wangshuai ---date:20230410  for：【issues/435】代码生成的日期控件赋默认值报错------------
          let valueFormat: string = "";
          if (componentProps) {
            valueFormat = componentProps?.valueFormat;
          }
          if (!valueFormat) {
            console.warn("未配置valueFormat,可能导致格式化错误！");
          }
          //update-end---author:wangshuai ---date:20230410  for：【issues/435】代码生成的日期控件赋默认值报错------------
          if (!Array.isArray(defaultValue)) {
            //update-begin---author:wangshuai ---date:20221124  for：[issues/215]列表页查询框（日期选择框）设置初始时间，一进入页面时，后台报日期转换类型错误的------------
            if (valueFormat) {
              // schema.defaultValue = dateUtil(defaultValue).format(valueFormat);
              // update-begin--author:liaozhiyang---date:20240529---for：【TV360X-346 】时间组件填写默认值有问题
              schema.defaultValue = dateUtil(defaultValue, valueFormat).format(valueFormat);
              // update-end--author:liaozhiyang---date:20240529---for：【TV360X-346 】时间组件填写默认值有问题
            } else {
              schema.defaultValue = dateUtil(defaultValue);
            }
            //update-end---author:wangshuai ---date:20221124  for：[issues/215]列表页查询框（日期选择框）设置初始时间，一进入页面时，后台报日期转换类型错误的------------
          } else {
            const def: dayjs.Dayjs[] = [];
            defaultValue.forEach((item) => {
              //update-begin---author:wangshuai ---date:20221124  for：[issues/215]列表页查询框（日期选择框）设置初始时间，一进入页面时，后台报日期转换类型错误的------------
              if (valueFormat) {
                // update-begin--author:liaozhiyang---date:20240529---for：【TV360X-346 】时间组件填写默认值有问题
                def.push(dateUtil(item, valueFormat).format(valueFormat));
                // update-end--author:liaozhiyang---date:20240529---for：【TV360X-346 】时间组件填写默认值有问题
              } else {
                def.push(dateUtil(item));
              }
              //update-end---author:wangshuai ---date:20221124  for：[issues/215]列表页查询框（日期选择框）设置初始时间，一进入页面时，后台报日期转换类型错误的------------
            });
            // update-begin--author:liaozhiyang---date:20240328---for：【issues/1114】rangepicker等时间控件报错（vue3.4以上版本有问题）
            def.forEach((item, index) => {
              defaultValue[index] = item;
            });
            // update-end--author:liaozhiyang---date:20240328---for：【issues/1114】rangepicker等时间控件报错（vue3.4以上版本有问题）
          }
        }
      }
      if (unref(getProps).showAdvancedButton) {
        return schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[];
      } else {
        return schemas as FormSchema[];
      }
    });

    const { handleToggleAdvanced } = useAdvanced({
      advanceState,
      emit,
      getProps,
      getSchema,
      formModel,
      defaultValueRef,
    });

    const { handleFormValues, initDefault } = useFormValues({
      getProps,
      defaultValueRef,
      getSchema,
      formModel,
    });

    useAutoFocus({
      getSchema,
      getProps,
      isInitedDefault: isInitedDefaultRef,
      formElRef: formElRef as Ref<FormActionType>,
    });

    const {
      handleSubmit,
      setFieldsValue,
      clearValidate,
      validate,
      validateFields,
      getFieldsValue,
      updateSchema,
      resetSchema,
      getSchemaByField,
      appendSchemaByField,
      removeSchemaByFiled,
      resetFields,
      scrollToField,
    } = useFormEvents({
      emit,
      getProps,
      formModel,
      getSchema,
      defaultValueRef,
      formElRef: formElRef as Ref<FormActionType>,
      schemaRef: schemaRef as Ref<FormSchema[]>,
      handleFormValues,
    });

    createFormContext({
      resetAction: resetFields,
      submitAction: handleSubmit,
    });

    watch(
      () => unref(getProps).model,
      () => {
        const { model } = unref(getProps);
        if (!model) return;
        setFieldsValue(model);
      },
      {
        immediate: true,
      }
    );

    watch(
      () => unref(getProps).schemas,
      (schemas) => {
        resetSchema(schemas ?? []);
      }
    );

    watch(
      () => getSchema.value,
      (schema) => {
        nextTick(() => {
          //  Solve the problem of modal adaptive height calculation when the form is placed in the modal
          modalFn?.redoModalHeight?.();
        });
        if (unref(isInitedDefaultRef)) {
          return;
        }
        if (schema?.length) {
          initDefault();
          isInitedDefaultRef.value = true;
        }
      }
    );

    async function setProps(formProps: Partial<FormProps>): Promise<void> {
      propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
    }

    //update-begin-author:taoyan date:2022-11-28 for: QQYUN-3121 【优化】表单视图问题#scott测试 8、此功能未实现
    const onFormSubmitWhenChange = useDebounceFn(handleSubmit, 300);
    function setFormModel(key: string, value: any) {
      formModel[key] = value;
      // update-begin--author:liaozhiyang---date:20230922---for：【issues/752】表单校验dynamicRules 无法 使用失去焦点后校验 trigger: 'blur'
      // const { validateTrigger } = unref(getBindValue);
      // if (!validateTrigger || validateTrigger === 'change') {
      //   validateFields([key]).catch((_) => {});
      // }
      // update-end--author:liaozhiyang---date:20230922---for：【issues/752】表单校验dynamicRules 无法 使用失去焦点后校验 trigger: 'blur'
      if (props.autoSearch === true) {
        onFormSubmitWhenChange();
      }
    }
    //update-end-author:taoyan date:2022-11-28 for: QQYUN-3121 【优化】表单视图问题#scott测试 8、此功能未实现

    function handleEnterPress(e: KeyboardEvent) {
      const { autoSubmitOnEnter } = unref(getProps);
      if (!autoSubmitOnEnter) return;
      if (e.key === 'Enter' && e.target && e.target instanceof HTMLElement) {
        const target: HTMLElement = e.target as HTMLElement;
        if (target && target.tagName && target.tagName.toUpperCase() == 'INPUT') {
          handleSubmit();
        }
      }
    }

    const formActionType: Partial<FormActionType> = {
      getFieldsValue,
      setFieldsValue,
      resetFields,
      updateSchema,
      resetSchema,
      setProps,
      getProps,
      getSchemaByField,
      removeSchemaByFiled,
      appendSchemaByField,
      clearValidate,
      validateFields,
      validate,
      submit: handleSubmit,
      scrollToField: scrollToField,
    };

    onMounted(() => {
      initDefault();
      emit('register', formActionType);
    });

    return {
      getBindValue,
      handleToggleAdvanced,
      handleEnterPress,
      formModel,
      defaultValueRef,
      advanceState,
      getRow,
      getProps,
      formElRef,
      getSchema,
      formActionType: formActionType as any,
      setFormModel,
      getFormClass,
      getFormActionBindProps: computed((): Recordable => ({ ...getProps.value, ...advanceState })),
      ...formActionType,
    };
  },
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-basic-form';

.@{prefix-cls} {
  .ant-form-item {
    &-label label::after {
      margin: 0 6px 0 2px;
    }

    &-with-help {
      margin-bottom: 0;
    }

    // update-begin--author:liaozhiyang---date:20240514---for：【QQYUN-9241】form表单上下间距大点
    //&:not(.ant-form-item-with-help) {
    //  margin-bottom: 24px;
    //}
    // update-begin--author:liaozhiyang---date:20240514---for：【QQYUN-9241】form表单上下间距大点
    // update-begin--author:liaozhiyang---date:20240620---for：【TV360X-1420】校验时闪动
    &-has-error {
      margin-bottom: 24px;
    }

    // update-end--author:liaozhiyang---date:20240620---for：【TV360X-1420】校验时闪动
    &.suffix-item {
      .ant-form-item-children {
        display: flex;
      }

      .ant-form-item-control {
        margin-top: 4px;
      }

      .suffix {
        display: inline-flex;
        padding-left: 6px;
        margin-top: 1px;
        line-height: 1;
        align-items: center;
      }
    }
  }

  /*【美化表单】form的字体改小一号*/
  /*    .ant-form-item-label > label{
      font-size: 13px;
    }
    .ant-form-item .ant-select {
      font-size: 13px;
    }
    .ant-select-item-option-selected {
      font-size: 13px;
    }
    .ant-select-item-option-content {
      font-size: 13px;
    }
    .ant-input {
      font-size: 13px;
    }*/
  /*【美化表单】form的字体改小一号*/

  .ant-form-explain {
    font-size: 14px;
  }

  &--compact {
    .ant-form-item {
      margin-bottom: 8px !important;
    }
  }

  // update-begin--author:liaozhiyang---date:20231017---for：【QQYUN-6566】BasicForm支持一行显示(inline)
  &.ant-form-inline {
    &>.ant-row {
      .ant-col {
        width: auto !important;
      }
    }
  }

  // update-end--author:liaozhiyang---date:20231017---for：【QQYUN-6566】BasicForm支持一行显示(inline)
}
</style>
